Skip to content

Add jobs API: listings, applications, and emails - #269

Merged
gregv merged 1 commit into
developfrom
feature/jobs-api
Aug 22, 2026
Merged

Add jobs API: listings, applications, and emails#269
gregv merged 1 commit into
developfrom
feature/jobs-api

Conversation

@gregv

@gregv gregv commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Backend for the new volunteer job board at ohack.dev/jobs. Frontend PR is linked in the comments.

What this adds

  • Two new Firestore collections: job_listings (doc id = URL slug) and job_applications
  • Public routes: list open roles, get one role. Drafts and hidden roles never show. Closed roles still load so shared links show a friendly "closed" page.
  • Applicant routes (login required): get a signed URL to upload a PDF resume, submit an application, and check "did I already apply?"
  • Admin routes (volunteer.admin): create/edit/hide/delete listings, review applications, and send a one-click accept or kind rejection email (with an optional personal note)

Emails (Resend)

  • Applicant confirmation asks them to reply within 5 days — a built-in test for responsiveness
  • Every application also sends an FYI to questions@ohack.org
  • All sends are skipped when ENVIRONMENT=test

Safety checks on submit

  • reCAPTCHA, rate limit, and a duplicate check (one application per person per role)
  • Resume and video URLs are re-checked on the server against the applicant's own storage path
  • Work sample must be at least 200 characters; visa acknowledgment is required

Seeding

python scripts/seed_job_listings.py --apply writes the three Fall 2026 roles as drafts. It skips roles that already exist, so admin edits are safe.

Testing

38 checks pass against MockFirestore covering the full lifecycle: create → publish → apply → duplicate 409 → confirm → kind rejection, plus auth gates and validator edge cases.

🤖 Generated with Claude Code

Volunteer job board backend for /jobs on the frontend. New api/jobs
blueprint with public listing routes, login-required apply routes
(signed-URL PDF resume upload, server-side URL verification, reCAPTCHA,
duplicate check), and volunteer.admin CRUD + one-click accept/reject
decision emails. Confirmation email carries a reply-within-5-days ask;
every application also sends an FYI to questions@ohack.org. Includes
validators, 300s caches, and an idempotent seed script for the three
Fall 2026 roles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gregv

gregv commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Frontend PR: opportunity-hack/frontend-ohack.dev#352 — deploy this backend PR first.

Comment thread api/jobs/jobs_views.py
data = request.get_json() or {}
payload, status = create_resume_upload_url(
auth_user.user_id, data.get("content_type"), data.get("content_length"))
return payload, status
Comment thread api/jobs/jobs_views.py
def admin_post_listing():
logger.info("POST /jobs/admin/listings called")
payload, status = admin_create_listing(request.get_json(), _actor_from_request())
return payload, status
Comment thread api/jobs/jobs_views.py
def admin_patch_listing(slug):
logger.info(f"PATCH /jobs/admin/listings/{slug} called")
payload, status = admin_update_listing(slug, request.get_json(), _actor_from_request())
return payload, status
Comment thread api/jobs/jobs_views.py
logger.info(f"POST /jobs/{slug}/apply called")
payload, status = submit_application(
auth_user.user_id, request.remote_addr, slug, request.get_json())
return payload, status
Comment thread api/jobs/jobs_views.py
def admin_post_listing():
logger.info("POST /jobs/admin/listings called")
payload, status = admin_create_listing(request.get_json(), _actor_from_request())
return payload, status
Comment thread api/jobs/jobs_views.py
def admin_patch_listing(slug):
logger.info(f"PATCH /jobs/admin/listings/{slug} called")
payload, status = admin_update_listing(slug, request.get_json(), _actor_from_request())
return payload, status
@gregv
gregv merged commit 344d826 into develop Aug 22, 2026
5 of 6 checks passed
@gregv
gregv deleted the feature/jobs-api branch August 22, 2026 22:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants